package com.example.utils;


import com.example.annotations.*;
import com.example.auth.LoginUtils;
import com.example.db.utils.SqlUtils;
import com.example.freemarker.FreemarkerConfig;
import com.example.freemarker.config.FreeMarkerConfig;
import com.example.job.JobUtils;
import com.example.model.HttpBody;
import com.example.model.HttpTemplateBody;
import io.vertx.core.Handler;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.StaticHandler;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Classname ObjectMaps
 * @Description TODO
 * @Date 2022/5/24 18:28
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class ObjectMaps {

        private  static Router router=null;

        private static Map<String,Handler<RoutingContext>> hadlerMap = new HashMap<>();

        //接口及接口名称
        private static Map<String,String> URL_NAME_MAP = new HashMap<>();

        public static void putHandler(String key,Handler<RoutingContext> handler){
              if(hadlerMap.containsKey(key)){
                clrearRoute(key);
                Handler<RoutingContext> hand=hadlerMap.get(key);
                hand=null;
              }
            ObjectMaps.hadlerMap.put(key, handler);
        }

        public static Handler<RoutingContext> getHandler(String key){
            return hadlerMap.get(key);
        }



        public static Router getRouter() {
            return ObjectMaps.router;
        }

        private static HashMap<String,Object> autuWirdemap = new HashMap<String, Object>();


        public static Object getObjectByClass(Class<?> cls){
            if(cls == null){
              return null;
            }
            String clsName=cls.getName();
            return autuWirdemap.get(clsName);
        }

        public static Object getObjectByName(String clsName){
            return autuWirdemap.get(clsName);
        }

        public static void createClazzList(List<Class<?>> cls,Router router) throws Exception{
            ObjectMaps.router=router;
            for (Class< ? > clazz : cls) {
                //添加容器
                addContains(clazz);
            }
            //系统公共
            systemCommon(router);
            //容器注入
            for (Class< ? > clazz : cls) {
                addFields(clazz);
            }
            //系统其他
            for (Class< ? > clazz : cls) {
                createClazz(clazz,router);
            }
            //初次执行

            //初始化
            SqlUtils.build(cls);
            //初始化Freemarker的宏引擎
            //初始化宏
            FreeMarkerConfig.init(cls);

        }


      public static void createClazzSystemList(List<Class<?>> cls,Router router) throws Exception{
                ObjectMaps.router=router;
                for (Class< ? > clazz : cls) {
                  //添加容器
                  addContains(clazz);
                }
                //容器注入
                for (Class< ? > clazz : cls) {
                  addFields(clazz);
                }
                //系统其他
                for (Class< ? > clazz : cls) {
                  createClazz(clazz,router);
                }

                //初始化数据库
                SqlUtils.build(cls);
                //初始化宏
                FreeMarkerConfig.init(cls);


      }

        public static void systemCommon(Router router){

            //初始化配置文件
            PropertiesUtils props = new PropertiesUtils();
            props.init();
            //初始化数据连接
            DataSourceUtils.init();

            String path=PropertiesUtils.getProperty("static");
            if(path != null){
                router.route("/*").handler(StaticHandler.create().setWebRoot(path).setCachingEnabled(false).setDefaultContentEncoding("UTF-8"));
            }else {
                router.route("/*").handler(StaticHandler.create("static"));
            }
            //初始化freemarker模板
            FreemarkerConfig freemarkerConfig = new FreemarkerConfig();
            autuWirdemap.put(FreemarkerConfig.class.getName(),freemarkerConfig);
            //初始化登录
            LoginUtils.init(router);
        }



        public static void setAutuWirdemap(String key,Object object){
            ObjectMaps.autuWirdemap.put(key, object);
        }

      /**
       * 添加到容器
       * @param clazz
       * @throws Exception
       */
      private static void addContains(Class< ? > clazz) throws Exception{
            Service service=clazz.getAnnotation(Service.class);
             Compontent component = clazz.getAnnotation(Compontent.class);
             if(service==null&& component==null){
                return;
             }
             //获取接口
             Class[] clazzList=clazz.getInterfaces();
             if(clazzList.length>0){
                 //只取第一个实现的
                Class<?> cls=clazzList[0];
                String clsName=cls.getName();
                Object value=clazz.newInstance();
                autuWirdemap.put(clsName,value);
             }else {
                 //默认用类名
                String clsName = clazz.getName();
                Object value = clazz.newInstance();
                autuWirdemap.put(clsName, value);
             }
        }

        /**
         *  属性注入
         *
         * @throws Exception
         */
        private static void addFields(Class< ? > clazz) throws Exception {
             if(clazz==null){
               return;
             }
               Compontent compontent=clazz.getAnnotation(Compontent.class);
               Service service=clazz.getAnnotation(Service.class);
               if(compontent == null && service == null){
                  return;
               }
              Class[] clazzList=clazz.getInterfaces();
               Object obj=null;
               if(clazzList.length>0){
                  Class<?> cls=clazzList[0];
                  obj=autuWirdemap.get(cls.getName());
               }else {
                    obj=autuWirdemap.get(clazz.getName());
               }


              Field[] fields=clazz.getDeclaredFields();
              for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                Autowired autowired=field.getAnnotation(Autowired.class);
                if(autowired != null){
                  field.setAccessible(true);
                  Class<?> fieldClass=field.getType();
                  Object val=autuWirdemap.get(fieldClass.getName());
                  field.set(obj,val);
                }
              }
            Method[] methods=clazz.getDeclaredMethods();
            for (Method method : methods) {
                Init init=method.getAnnotation(Init.class);
                if (init != null) {
                    method.invoke(obj);
                }
            }
        }

//        private static void Init(Class< ? > clazz) throws InvocationTargetException, IllegalAccessException {
//            if(clazz == null){
//                return;
//            }
//            Compontent compontent=clazz.getAnnotation(Compontent.class);
//            Service service=clazz.getAnnotation(Service.class);
//            RestController restController=clazz.getAnnotation(RestController.class);
//            if(compontent==null&& service == null && restController == null){
//                return;
//            }
//            Method[] methods=clazz.getDeclaredMethods();
//            for (Method method : methods) {
//                Init init=method.getAnnotation(Init.class);
//                if (init != null) {
//                    Object obj=ObjectMaps.getObjectByClass(clazz);
//                    method.invoke(obj);
//                }
//            }
//        }


        private static void createClazz(Class<?> cls,  Router router) throws Exception{
          if(cls==null){
            return;
          }
          RouteMapping routeMap=cls.getAnnotation(RouteMapping.class);
          RestController restController=cls.getAnnotation(RestController.class);
          Controller controller=cls.getAnnotation(Controller.class);
          Auth auth=cls.getAnnotation(Auth.class);
          if(routeMap == null && restController==null && controller==null){
            return;
          }


          Object objRouteMapping=cls.newInstance();
          String url=null;
          if(routeMap!=null){
              url=routeMap.value();
          }else if(restController != null){
              url=restController.value();
          }else {
              url=controller.value();
          }

          Field[] fields=cls.getDeclaredFields();
          for (int i = 0; i < fields.length; i++) {
              Field field = fields[i];
              Autowired autowired=field.getAnnotation(Autowired.class);
              if(autowired != null){
                field.setAccessible(true);
                  Class<?> fieldClass=field.getType();
                  Object val=autuWirdemap.get(fieldClass.getName());
                  field.setAccessible(true);
                  field.set(objRouteMapping,val);
              }
          }
          Method[] method = cls.getDeclaredMethods();
          for (int i = 0; i < method.length ; i++) {
            Method me = method[i];
            RequestMethod requestMethod=me.getAnnotation(RequestMethod.class);
            GetMapping getMapping=me.getAnnotation(GetMapping.class);
            PostMapping postMapping = me.getAnnotation(PostMapping.class);
            Auth authMethod=me.getAnnotation(Auth.class);
            UploadFile uploadFile=me.getAnnotation(UploadFile.class);
            if(requestMethod==null && getMapping == null && postMapping == null && uploadFile==null){
                continue;
            }
            Class<?>[] clazzs=me.getParameterTypes();
            Handler<RoutingContext> handler=null;

            if(controller!=null){
              //模板
              HttpTemplateBody httpTemplateBody=new HttpTemplateBody();
              handler=httpTemplateBody.body(me,objRouteMapping,clazzs);
            }else {
              //返回后台信息
              HttpBody httpBody=new HttpBody();
              handler=httpBody.body(me,objRouteMapping,clazzs);
            }

            String urlPath=null;
            String urlPathName=null;

            if(requestMethod!=null){
               urlPath=url+""+requestMethod.value();
               urlPathName=requestMethod.desc();
              //此处的逻辑主要是覆盖上次产生的对象
              putHandler(urlPath,handler);
              handler=getHandler(urlPath);

              router.route(urlPath).handler(handler);
            }else if(getMapping!=null){
                urlPath=url + ""+ getMapping.value();
                urlPathName=getMapping.desc();
              //此处的逻辑主要是覆盖上次产生的对象
              putHandler(urlPath,handler);
              handler=getHandler(urlPath);

                router.get(urlPath).handler(handler);
            }else if (postMapping!=null){
                //添加请求体处理
                urlPath=url + ""+ postMapping.value();
                urlPathName=postMapping.desc();
              //此处的逻辑主要是覆盖上次产生的对象
                putHandler(urlPath,handler);
                handler=getHandler(urlPath);

                router.post(urlPath).handler(BodyHandler.create());
                router.post(urlPath ).handler(handler);
            }else if(uploadFile !=null){
                urlPath=url + ""+ uploadFile.value();
                urlPathName=uploadFile.desc();
                System.out.println("[文件上传]"+urlPath+" "+cls.getName());

                putHandler(urlPath,handler);
                handler=getHandler(urlPath);

                String path=uploadFile.path();
                if("".equals(uploadFile.path())){
                    path=PathUtils.getPath();
                }
                int size=uploadFile.size();

                router.route()
                        .handler(BodyHandler.create().setUploadsDirectory(path).setBodyLimit(size));
                router.post(urlPath).handler(handler);

            }else  {
               urlPath=url + ""+ postMapping.value();
                //此处的逻辑主要是覆盖上次产生的对象
                putHandler(urlPath,handler);
                handler=getHandler(urlPath);
                router.route(urlPath).handler(handler);
            }
            if(auth!=null || authMethod!= null){
                //添加不同登录
                LoginUtils.addFreeLoginUrl(urlPath);
            }else {
                //判断url是否存在
                boolean exist=LoginUtils.existFreeLoginUrl(urlPath);
                if(exist){
                  //如果存在
                  LoginUtils.removeUrl(urlPath);
                }
            }
            addURL_NAME(urlPath,urlPathName);
              SimpleDateFormat dft=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                System.out.println("【"+dft.format(new Date())+"】  "+urlPath+" 添加成功");
          }
        }

        private static void addURL_NAME(String url,String name){
            if(name==null){
                name="";
            }
            ObjectMaps.URL_NAME_MAP.put(url,name);
        }

        public static String getUrlName(String url){
           String name= ObjectMaps.URL_NAME_MAP.get(url);
           if(name == null){
               return "";
           }
           return name;
        }

        //清除路由
        public static void clrearRoute(String url){
            Router router=getRouter();
            if(router!=null){
              router.getRoutes().stream()
                .filter(route -> route.getPath() != null && route.getPath().startsWith(url))
                .forEach(route -> route.remove());
            }
        }

        public static void createClazzList(List<Class<?>>classList) throws Exception{
            if (classList == null) {
                return;
            }
            if(ObjectMaps.getRouter()!=null){
              createClazzSystemList(classList,ObjectMaps.getRouter());
            }
        }



        public static void createClazz(Class<?> cls) throws Exception{
          if(cls==null){
            return;
          }
          if(ObjectMaps.getRouter()!=null){
              createClazz(cls,ObjectMaps.getRouter());
          }
        }



}
